package com.kexio.user.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.kexio.user.entity.Menu;

/**
 * 菜单数据访问层
 * 
 * 基于MyBatis Plus的菜单数据访问接口，提供：
 * - 基础CRUD操作（继承自BaseMapper）
 * - 菜单树形结构查询
 * - 用户菜单权限查询
 * - 菜单层级关系处理
 * - 多租户数据隔离
 * 
 * @author Kexio Team
 * @since 1.0.0
 */
@Mapper
public interface MenuMapper extends BaseMapper<Menu> {
    
    // ==================== 基础查询 ====================
    
    /**
     * 根据菜单编码和租户ID查询菜单
     * 
     * @param menuCode 菜单编码
     * @param tenantId 租户ID
     * @return 菜单信息
     */
    Menu selectByCodeAndTenant(@Param("menuCode") String menuCode, @Param("tenantId") String tenantId);
    
    /**
     * 查询租户下的所有菜单
     * 
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> selectByTenant();
    
    /**
     * 根据菜单类型查询菜单列表
     * 
     * @param menuType 菜单类型
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> selectByType(@Param("menuType") String menuType, @Param("tenantId") String tenantId);
    
    // ==================== 菜单树形结构查询 ====================
    
    /**
     * 查询菜单的直接子菜单
     * 
     * @param parentMenuId 父菜单ID
     * @param tenantId 租户ID
     * @return 子菜单列表
     */
    List<Menu> selectChildMenus(@Param("parentMenuId") Long parentMenuId, @Param("tenantId") String tenantId);
    
    /**
     * 查询菜单的所有祖先菜单（向上查询）
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 祖先菜单列表
     */
    List<Menu> selectAncestorMenus(@Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    /**
     * 查询菜单的所有后代菜单（向下查询）
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 后代菜单列表
     */
    List<Menu> selectDescendantMenus(@Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    /**
     * 查询根菜单列表（没有父菜单的菜单）
     * 
     * @param tenantId 租户ID
     * @return 根菜单列表
     */
    List<Menu> selectRootMenus(@Param("tenantId") String tenantId);
    
    /**
     * 查询完整菜单树（用于构建树形结构）
     * 
     * @param tenantId 租户ID
     * @return 所有菜单列表（按sort_order排序）
     */
    List<Menu> selectMenuTree(@Param("tenantId") String tenantId);
    
    // ==================== 用户菜单权限查询 ====================
    
    /**
     * 查询用户有权限访问的菜单列表
     * 
     * 通过用户角色和权限关联查询用户可见的菜单
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> selectUserMenus(@Param("userId") String userId, @Param("tenantId") String tenantId);
    
    /**
     * 查询用户有权限访问的菜单树
     * 
     * 递归查询用户可见的完整菜单树结构
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 用户菜单树列表
     */
    List<Menu> selectUserMenuTree(@Param("userId") String userId, @Param("tenantId") String tenantId);
    
    /**
     * 查询用户在指定菜单下的操作权限
     * 
     * @param userId 用户ID
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 权限编码列表
     */
    List<String> selectUserMenuPermissions(@Param("userId") String userId, @Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    // ==================== 角色菜单查询 ====================
    
    /**
     * 查询角色关联的菜单列表
     * 
     * @param roleId 角色ID
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> selectRoleMenus(@Param("roleId") String roleId, @Param("tenantId") String tenantId);
    
    /**
     * 查询拥有指定菜单访问权限的角色列表
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 角色列表
     */
    List<com.kexio.user.entity.Role> selectMenuRoles(@Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    // ==================== 权限关联查询 ====================
    
    /**
     * 查询菜单关联的权限列表
     * 
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 权限列表
     */
    List<com.kexio.user.entity.Permission> selectMenuPermissions(@Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    /**
     * 查询权限关联的菜单列表
     * 
     * @param permissionId 权限ID
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> selectPermissionMenus(@Param("permissionId") String permissionId, @Param("tenantId") String tenantId);
    
    // ==================== 导航菜单查询 ====================
    
    /**
     * 查询用户的导航菜单列表
     * 
     * 查询用户有权限且显示在导航中的菜单
     * 
     * @param userId 用户ID
     * @param tenantId 租户ID
     * @return 导航菜单列表
     */
    List<Menu> selectUserNavMenus(@Param("userId") String userId, @Param("tenantId") String tenantId);
    
    /**
     * 查询面包屑导航路径
     * 
     * 根据当前菜单查询到根菜单的完整路径
     * 
     * @param menuId 当前菜单ID
     * @param tenantId 租户ID
     * @return 面包屑菜单列表（从根到当前）
     */
    List<Menu> selectBreadcrumbPath(@Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    // ==================== 菜单检查 ====================
    
    /**
     * 检查菜单编码是否存在
     * 
     * @param menuCode 菜单编码
     * @param tenantId 租户ID
     * @return 是否存在
     */
    boolean existsByCode(@Param("menuCode") String menuCode, @Param("tenantId") String tenantId);
    
    /**
     * 检查用户是否有菜单访问权限
     * 
     * @param userId 用户ID
     * @param menuId 菜单ID
     * @param tenantId 租户ID
     * @return 是否有权限
     */
    boolean hasMenuAccess(@Param("userId") String userId, @Param("menuId") Long menuId, @Param("tenantId") String tenantId);
    
    /**
     * 检查菜单路径唯一性
     * 
     * @param menuPath 菜单路径
     * @param excludeMenuId 排除的菜单ID（用于更新时检查）
     * @param tenantId 租户ID
     * @return 是否唯一
     */
    boolean isMenuPathUnique(@Param("menuPath") String menuPath, @Param("excludeMenuId") Long excludeMenuId, @Param("tenantId") String tenantId);
    
    // ==================== 统计查询 ====================
    
    /**
     * 统计租户菜单总数
     * 
     * @param tenantId 租户ID
     * @return 菜单总数
     */
    Long countMenusByTenant(@Param("tenantId") String tenantId);
    
    /**
     * 统计启用的菜单数量
     * 
     * @param tenantId 租户ID
     * @return 启用菜单数
     */
    Long countActiveMenus(@Param("tenantId") String tenantId);
    
    /**
     * 统计各类型菜单数量
     * 
     * @param tenantId 租户ID
     * @return 类型统计结果 Map<菜单类型, 数量>
     */
    List<java.util.Map<String, Object>> countMenusByType(@Param("tenantId") String tenantId);
    
    // ==================== 状态查询 ====================
    
    /**
     * 查询启用状态的菜单列表
     * 
     * @param tenantId 租户ID
     * @return 启用菜单列表
     */
    List<Menu> selectActiveMenus(@Param("tenantId") String tenantId);
    
    /**
     * 查询指定状态的菜单列表
     * 
     * @param status 菜单状态
     * @param tenantId 租户ID
     * @return 菜单列表
     */
    List<Menu> selectMenusByStatus(@Param("status") String status, @Param("tenantId") String tenantId);
    
    /**
     * 查询可见的菜单列表（status为ACTIVE且visible为true）
     * 
     * @param tenantId 租户ID
     * @return 可见菜单列表
     */
    List<Menu> selectVisibleMenus(@Param("tenantId") String tenantId);
    
    // ==================== 排序相关 ====================
    
    /**
     * 查询同级菜单的最大排序号
     * 
     * @param parentMenuId 父菜单ID
     * @param tenantId 租户ID
     * @return 最大排序号
     */
    Integer getMaxSortOrderByParent(@Param("parentMenuId") Long parentMenuId, @Param("tenantId") String tenantId);
    
    /**
     * ✅ 批量更新菜单排序（一条SQL搞定）
     * 
     * @param menuIdSortMap 菜单ID->排序号映射
     * @return 更新的记录数
     */
    int batchUpdateMenuSort(@Param("menuIdSortMap") java.util.Map<String, Integer> menuIdSortMap);
}
